/* House - Decompiled by JODE
 * Visit http://jode.sourceforge.net/
 */
package com.maddox.il2.objects.buildings;
import com.maddox.JGP.Matrix4d;
import com.maddox.JGP.Point3d;
import com.maddox.JGP.Vector3f;
import com.maddox.il2.ai.Explosion;
import com.maddox.il2.ai.MsgExplosionListener;
import com.maddox.il2.ai.MsgShotListener;
import com.maddox.il2.ai.Shot;
import com.maddox.il2.ai.World;
import com.maddox.il2.engine.Actor;
import com.maddox.il2.engine.ActorHMesh;
import com.maddox.il2.engine.ActorSpawn;
import com.maddox.il2.engine.ActorSpawnArg;
import com.maddox.il2.engine.Engine;
import com.maddox.il2.engine.MeshShared;
import com.maddox.il2.engine.Orient;
import com.maddox.il2.objects.ActorAlign;
import com.maddox.il2.objects.Statics;
import com.maddox.il2.objects.effects.Explosions;
import com.maddox.rts.Finger;
import com.maddox.rts.Message;
import com.maddox.rts.SectFile;
import com.maddox.rts.SoftClass;
import com.maddox.rts.Spawn;

public final class House extends ActorHMesh
    implements MsgExplosionListener, MsgShotListener, ActorAlign, SoftClass
{
    private Properties prop = null;
    private static final int MAT_WOOD = 0;
    private static final int MAT_BRICK = 1;
    private static final int MAT_STEEL = 2;
    private static final int MAT_FLESH = 3;
    private static final int N_MAT_TYPES = 4;
    private static float[][][] PenetrateEnergyToKill = null;
    private static float[][] PenetrateThickness = null;
    private static final float KinEnergy_4 = 511.22504F;
    private static final float KinEnergy_7_62 = 2453.8801F;
    private static final float KinEnergy_12_7 = 10140.0F;
    private static final float KinEnergy_20 = 23400.0F;
    private static final float KinEnergy_37 = 131400.0F;
    private static final float KinEnergy_45 = 252000.0F;
    private static final float KinEnergy_50 = 369000.0F;
    private static final float KinEnergy_75 = 1224000.0F;
    private static final float KinEnergy_100 = 3295500.0F;
    private static final float KinEnergy_203 = 5120000.0F;
    private static Point3d p = new Point3d();
    private static Orient o = new Orient();
    private static Vector3f n = new Vector3f();
    private static float[] probab = new float[2];
    
    public static class Properties
    {
	public String SoftClassInnerName = null;
	public int FingerOfFullClassName = 0;
	public String MESH0_NAME = "3do/BuildingsGeneral/NameNotSpecified.sim";
	public String MESH1_NAME
	    = "3do/BuildingsGeneral/DMG/NameNotSpecified.sim";
	private boolean meshTested = false;
	public float ADD_HEIGHT_0 = 0.0F;
	public float ADD_HEIGHT_1 = 0.0F;
	public boolean ALIGN_TO_LAND_NORMAL = false;
	public boolean IGNORE_SHADOW_DATA = false;
	public int MAT_TYPE = -1;
	public int EFF_BODY_MATERIAL = -1;
	public int EXPL_TYPE = -1;
	public float PANZER = 0.0010F;
	public float MIN_TNT = 0.07F;
	public float MAX_TNT = 0.071F;
	public float PROBAB_DEATH_WHEN_EXPLOSION = 0.4F;
	public boolean bInitHeight0 = false;
	public boolean bInitHeight1 = false;
	public float heightAboveLandSurface0;
	public float heightAboveLandSurface1;
    }
    
    public static class SPAWN implements ActorSpawn
    {
	public Class cls = this.getClass().getDeclaringClass();
	public Properties prop;
	
	private static float getF(SectFile sectfile, String string,
				  String string_0_, float f, float f_1_) {
	    float f_2_ = sectfile.get(string, string_0_, -9865.345F);
	    if (f_2_ == -9865.345F || f_2_ < f || f_2_ > f_1_) {
		if (f_2_ == -9865.345F)
		    System.out.println("House: Value of [" + string + "]:<"
				       + string_0_ + "> " + "not found");
		else
		    System.out.println("House: Value of [" + string + "]:<"
				       + string_0_ + "> (" + f_2_ + ")"
				       + " is out of range (" + f + ";" + f_1_
				       + ")");
		throw new RuntimeException("Can't set property");
	    }
	    return f_2_;
	}
	
	private static float getF(SectFile sectfile, String string,
				  String string_3_, float f, float f_4_,
				  float f_5_) {
	    float f_6_ = sectfile.get(string, string_3_, -9865.345F);
	    if (f_6_ == -9865.345F)
		return f;
	    if (f_6_ < f_4_ || f_6_ > f_5_) {
		System.out.println("House: Value of [" + string + "]:<"
				   + string_3_ + "> (" + f_6_ + ")"
				   + " is out of range (" + f_4_ + ";" + f_5_
				   + ")");
		throw new RuntimeException("Can't set property");
	    }
	    return f_6_;
	}
	
	private static String getS(SectFile sectfile, String string,
				   String string_7_) {
	    String string_8_ = sectfile.get(string, string_7_);
	    if (string_8_ == null || string_8_.length() <= 0) {
		System.out.print("House: Parameter [" + string + "]:<"
				 + string_7_ + "> ");
		System.out
		    .println(string_8_ == null ? "not found" : "is empty");
		throw new RuntimeException("Can't set property");
	    }
	    return string_8_;
	}
	
	private static Properties LoadHouseProperties
	    (SectFile sectfile, String string, String string_9_,
	     String string_10_) {
	    Properties properties = new Properties();
	    properties.SoftClassInnerName = string_10_;
	    properties.FingerOfFullClassName = Finger.Int(string_9_);
	    String string_11_ = sectfile.get(string, "equals");
	    if (string_11_ == null || string_11_.length() <= 0)
		string_11_ = string;
	    properties.MESH0_NAME = getS(sectfile, string, "MeshLive");
	    properties.MESH1_NAME = sectfile.get(string, "MeshDead");
	    if (properties.MESH1_NAME == null)
		getS(sectfile, string, "MeshDead");
	    if (properties.MESH1_NAME.equals(""))
		properties.MESH1_NAME = null;
	    properties.ADD_HEIGHT_0
		= getF(sectfile, string_11_, "AddHeightLive", 0.0F, -100.0F,
		       100.0F);
	    properties.ADD_HEIGHT_1
		= getF(sectfile, string_11_, "AddHeightDead", 0.0F, -100.0F,
		       100.0F);
	    properties.ALIGN_TO_LAND_NORMAL
		= (getF(sectfile, string_11_, "AlignToLand", 0.0F, 0.0F, 1.0F)
		   > 0.0F);
	    properties.ALIGN_TO_LAND_NORMAL
		= (getF(sectfile, string_11_, "AlignToLand", 0.0F, 0.0F, 1.0F)
		   > 0.0F);
	    properties.IGNORE_SHADOW_DATA = false;
	    if (sectfile.get(string, "IgnoreShadowData") != null)
		properties.IGNORE_SHADOW_DATA = true;
	    properties.PANZER
		= getF(sectfile, string_11_, "Panzer", 1.0E-4F, 50.0F);
	    String string_12_ = getS(sectfile, string_11_, "Body");
	    if (string_12_.equalsIgnoreCase("WoodSmall")) {
		properties.MAT_TYPE = 0;
		properties.EFF_BODY_MATERIAL = 3;
		properties.EXPL_TYPE = 0;
		properties.MIN_TNT = 0.25F * (properties.PANZER / 0.025F);
		properties.MAX_TNT = properties.MIN_TNT * 2.0F;
		properties.PROBAB_DEATH_WHEN_EXPLOSION = 0.01F;
	    } else if (string_12_.equalsIgnoreCase("WoodMiddle")) {
		properties.MAT_TYPE = 0;
		properties.EFF_BODY_MATERIAL = 3;
		properties.EXPL_TYPE = 1;
		properties.MIN_TNT = 5.0F * (properties.PANZER / 0.15F);
		properties.MAX_TNT = properties.MIN_TNT * 1.7F;
		properties.PROBAB_DEATH_WHEN_EXPLOSION = 0.01F;
	    } else if (string_12_.equalsIgnoreCase("RockMiddle")) {
		properties.MAT_TYPE = 1;
		properties.EFF_BODY_MATERIAL = 4;
		properties.EXPL_TYPE = 2;
		properties.MIN_TNT = 6.0F * (properties.PANZER / 0.12F);
		properties.MAX_TNT = properties.MIN_TNT * 1.7F;
		properties.PROBAB_DEATH_WHEN_EXPLOSION = 0.01F;
	    } else if (string_12_.equalsIgnoreCase("RockBig")) {
		properties.MAT_TYPE = 1;
		properties.EFF_BODY_MATERIAL = 4;
		properties.EXPL_TYPE = 3;
		properties.MIN_TNT = 12.0F * (properties.PANZER / 0.24F);
		properties.MAX_TNT = properties.MIN_TNT * 1.7F;
		properties.PROBAB_DEATH_WHEN_EXPLOSION = 0.05F;
	    } else if (string_12_.equalsIgnoreCase("RockHuge")) {
		properties.MAT_TYPE = 1;
		properties.EFF_BODY_MATERIAL = 4;
		properties.EXPL_TYPE = 4;
		properties.MIN_TNT = 30.0F * (properties.PANZER / 0.48F);
		properties.MAX_TNT = properties.MIN_TNT * 1.7F;
		properties.PROBAB_DEATH_WHEN_EXPLOSION = 0.05F;
	    } else if (string_12_.equalsIgnoreCase("FuelSmall")) {
		properties.MAT_TYPE = 2;
		properties.EFF_BODY_MATERIAL = 2;
		properties.EXPL_TYPE = 5;
		properties.MIN_TNT = 0.2F * (properties.PANZER / 0.0020F);
		properties.MAX_TNT = properties.MIN_TNT * 1.7F;
		properties.PROBAB_DEATH_WHEN_EXPLOSION = 0.01F;
	    } else if (string_12_.equalsIgnoreCase("FuelBig")) {
		properties.MAT_TYPE = 2;
		properties.EFF_BODY_MATERIAL = 2;
		properties.EXPL_TYPE = 6;
		properties.MIN_TNT = 0.8F * (properties.PANZER / 0.0080F);
		properties.MAX_TNT = properties.MIN_TNT * 1.7F;
		properties.PROBAB_DEATH_WHEN_EXPLOSION = 0.01F;
	    } else if (string_12_.equalsIgnoreCase("Flesh")) {
		properties.MAT_TYPE = 3;
		properties.EFF_BODY_MATERIAL = 3;
		properties.EXPL_TYPE = 0;
		properties.MIN_TNT = 0.01F * (properties.PANZER / 0.0020F);
		properties.MAX_TNT = properties.MIN_TNT * 1.7F;
		properties.PROBAB_DEATH_WHEN_EXPLOSION = 0.1F;
	    } else {
		System.out.println("House: Undefined Body type in class '"
				   + string_9_ + "'");
		System.out.println
		    ("Allowed body types are:WoodSmall,WoodMiddle,RockMiddle,RockBig,RockHuge,FuelSmall,FuelBig,Flesh");
		throw new RuntimeException("Can't register house object");
	    }
	    return properties;
	}
	
	protected SPAWN(String string) {
	    String string_13_ = cls.getName();
	    String string_14_
		= string_13_.substring(string_13_.lastIndexOf('.') + 1);
	    String string_15_ = string_14_ + '$' + string;
	    String string_16_ = string_13_ + '$' + string;
	    SectFile sectfile = Statics.getBuildingsFile();
	    String string_17_ = null;
	    int i = sectfile.sections();
	    for (int i_18_ = 0; i_18_ < i; i_18_++) {
		if (sectfile.sectionName(i_18_).endsWith(string_15_)) {
		    string_17_ = sectfile.sectionName(i_18_);
		    break;
		}
	    }
	    if (string_17_ == null) {
		System.out
		    .println("House: Section " + string_15_ + " not found");
		throw new RuntimeException("Can't register spawner");
	    }
	    try {
		prop = LoadHouseProperties(sectfile, string_17_, string_16_,
					   string);
	    } catch (Exception exception) {
		System.out.println(exception.getMessage());
		exception.printStackTrace();
		System.out.println("Problem in house spawn registration: "
				   + string_16_);
	    }
	    Spawn.add_SoftClass(string_16_, this);
	}
	
	public Actor actorSpawn(ActorSpawnArg actorspawnarg) {
	    Object object = null;
	    House house;
	    try {
		house = (House) cls.newInstance();
	    } catch (Exception exception) {
		System.out.println(exception.getMessage());
		exception.printStackTrace();
		return null;
	    }
	    house.prop = prop;
	    if (!actorspawnarg.armyExist) {
		actorspawnarg.armyExist = true;
		actorspawnarg.army = 0;
	    }
	    actorspawnarg.setStationaryNoIcon(house);
	    try {
		house.activateMesh();
	    } catch (RuntimeException runtimeexception) {
		house.destroy();
		throw runtimeexception;
	    }
	    if (!house.prop.meshTested && house.mesh().collisionR() <= 0.0F)
		System.out.println("##### House without collision ("
				   + house.prop.MESH0_NAME + ")");
	    house.prop.meshTested = true;
	    return house;
	}
    }
    
    public static void registerSpawner(String string) {
	new SPAWN(string);
    }
    
    public String fullClassName() {
	return this.getClass().getName() + "$" + prop.SoftClassInnerName;
    }
    
    public int fingerOfFullClassName() {
	return prop.FingerOfFullClassName;
    }
    
    public String getMeshLiveName() {
	return prop.MESH0_NAME;
    }
    
    private static final boolean RndB(float f) {
	return World.Rnd().nextFloat(0.0F, 1.0F) < f;
    }
    
    private static final float RndF(float f, float f_19_) {
	return World.Rnd().nextFloat(f, f_19_);
    }
    
    private static final void internalerrror(int i) {
	System.out.println("*** Internal error#" + i + " in House ***");
	throw new RuntimeException("Can't initialize House");
    }
    
    private static final void InitTablesOfEnergyToKill() {
	PenetrateEnergyToKill = new float[4][][];
	PenetrateThickness = new float[4][];
	PenetrateThickness[0] = new float[] { 0.025F, 0.15F };
	PenetrateEnergyToKill[0]
	    = new float[][] { { 23400.0F, 131400.0F, 252000.0F },
			      { 131400.0F, 369000.0F, 1224000.0F } };
	PenetrateThickness[1] = new float[] { 0.12F, 0.24F };
	PenetrateEnergyToKill[1]
	    = new float[][] { { 131400.0F, 252000.0F, 3295500.0F },
			      { 369000.0F, 3295500.0F, 5120000.0F } };
	PenetrateThickness[2] = new float[] { 0.0020F, 0.0080F };
	PenetrateEnergyToKill[2]
	    = new float[][] { { 511.22504F, 2453.8801F, 23400.0F },
			      { 2453.8801F, 10140.0F, 23400.0F } };
	PenetrateThickness[3] = new float[] { 0.025F, 0.15F };
	PenetrateEnergyToKill[3]
	    = new float[][] { { 23400.0F, 131400.0F, 252000.0F },
			      { 131400.0F, 369000.0F, 1224000.0F } };
	for (int i = 0; i < 4; i++) {
	    if ((double) Math.abs(PenetrateThickness[i][0]
				  - PenetrateThickness[i][1])
		< 0.0010)
		internalerrror(1);
	    for (int i_20_ = 0; i_20_ <= 1; i_20_++) {
		float[] fs = PenetrateEnergyToKill[i][i_20_];
		if ((double) (fs[1] - fs[0]) < 0.0010
		    || (double) (fs[2] - fs[1]) < 0.0010)
		    internalerrror(2);
	    }
	    float f = Math.min(PenetrateEnergyToKill[i][0][0],
			       PenetrateEnergyToKill[i][1][0]);
	    float f_21_ = Math.max(PenetrateEnergyToKill[i][0][2],
				   PenetrateEnergyToKill[i][1][2]);
	    for (int i_22_ = 0; i_22_ <= 100; i_22_++) {
		float f_23_ = f + (f_21_ - f) * (float) i_22_ / 100.0F;
		float f_24_ = ComputeProbabOfPenetrateKill(i, 0, f_23_);
		float f_25_ = ComputeProbabOfPenetrateKill(i, 1, f_23_);
		if (f_24_ < f_25_) {
		    System.out.println(i + " i,e0,e1,e:" + i_22_ + " " + f
				       + " " + f_21_ + " " + f_23_
				       + " prob0,1: " + f_24_ + " " + f_25_);
		    internalerrror(3);
		}
	    }
	}
    }
    
    private static final float ComputeProbabOfPenetrateKill(int i, int i_26_,
							    float f) {
	float[] fs = PenetrateEnergyToKill[i][i_26_];
	float f_27_;
	float f_28_;
	if (f < fs[1]) {
	    if (f < fs[0])
		return 0.0F;
	    f_27_ = 0.20000002F / (fs[1] - fs[0]);
	    f_28_ = 0.1F - fs[0] * f_27_;
	} else {
	    if (f >= fs[2])
		return 1.0F;
	    f_27_ = 0.7F / (fs[2] - fs[1]);
	    f_28_ = 0.3F - fs[1] * f_27_;
	}
	return f * f_27_ + f_28_;
    }
    
    private final float ComputeProbabOfPenetrateKill(float f, int i) {
	if (i <= 0)
	    return 0.0F;
	float f_29_ = ComputeProbabOfPenetrateKill(prop.MAT_TYPE, 0, f);
	float f_30_ = ComputeProbabOfPenetrateKill(prop.MAT_TYPE, 1, f);
	float[] fs = PenetrateThickness[prop.MAT_TYPE];
	float f_31_ = (f_30_ - f_29_) / (fs[1] - fs[0]);
	float f_32_ = f_29_ - fs[0] * f_31_;
	float f_33_ = prop.PANZER * f_31_ + f_32_;
	if (f_33_ < 0.1F)
	    f_33_ = 0.0F;
	else if (f_33_ >= 1.0F)
	    f_33_ = 1.0F;
	else if (i > 1)
	    f_33_
		= 1.0F - (float) Math.pow((double) (1.0F - f_33_), (double) i);
	return f_33_;
    }
    
    public void msgShot(Shot shot) {
	shot.bodyMaterial = prop.EFF_BODY_MATERIAL;
	if (isAlive() && !(shot.power <= 0.0F)) {
	    if (prop.MAT_TYPE == 3) {
		if (shot.powerType == 1)
		    die(shot.initiator, true);
		else if (!(shot.v.length() < 20.0))
		    die(shot.initiator, true);
	    } else if (shot.powerType == 1) {
		if (prop.MAT_TYPE == 2) {
		    float f = shot.power * RndF(0.75F, 1.15F);
		    float f_34_
			= 0.256F * (float) Math.sqrt(Math.sqrt((double) f));
		    if (!(prop.PANZER > f_34_))
			die(shot.initiator, true);
		}
	    } else {
		float f = ComputeProbabOfPenetrateKill(shot.power, 1);
		if (RndB(f))
		    die(shot.initiator, true);
	    }
	}
    }
    
    public void msgExplosion(Explosion explosion) {
	if (isAlive() && !(explosion.power <= 0.0F)) {
	    if (prop.MAT_TYPE == 3) {
		if (Explosion.killable(this,
				       explosion.receivedTNT_1meter(this),
				       0.0050F, 0.1F, 0.0F))
		    die(explosion.initiator, true);
	    } else {
		int i = explosion.powerType;
		if (explosion == null) {
		    /* empty */
		}
		if (i == 1) {
		    float[] fs = new float[6];
		    mesh().getBoundBox(fs);
		    pos.getAbs(p);
		    p.x = p.x - (double) fs[0] + (double) (fs[3] - fs[0]);
		    p.y = p.y - (double) fs[1] + (double) (fs[4] - fs[1]);
		    p.z = p.z - (double) fs[2] + (double) (fs[5] - fs[2]);
		    float[] fs_35_ = new float[2];
		    explosion.computeSplintersHit(p, mesh().collisionR(), 0.7F,
						  fs_35_);
		    if (explosion == null) {
			/* empty */
		    }
		    float f = 0.015F * fs_35_[1] * fs_35_[1] * 0.5F;
		    float f_36_
			= ComputeProbabOfPenetrateKill(f, (int) (fs_35_[0]
								 + 0.5F));
		    if (RndB(f_36_))
			die(explosion.initiator, true);
		} else {
		    int i_37_ = explosion.powerType;
		    if (explosion == null) {
			/* empty */
		    }
		    if (i_37_ == 0) {
			if (Explosion.killable(this,
					       explosion.receivedPower(this),
					       prop.MIN_TNT, prop.MAX_TNT,
					       (prop
						.PROBAB_DEATH_WHEN_EXPLOSION)))
			    die(explosion.initiator, true);
		    } else if (prop.MAT_TYPE != 1)
			die(explosion.initiator, true);
		}
	    }
	}
    }
    
    protected void runDeathShow() {
	if (prop.MAT_TYPE != 3) {
	    float[] fs = new float[6];
	    mesh().getBoundBox(fs);
	    Explosions.HouseExplode(prop.EXPL_TYPE, pos.getAbs(), fs);
	}
    }
    
    private void die(Actor actor, boolean bool) {
	if (isAlive()) {
	    if (bool)
		runDeathShow();
	    World.onActorDied(this, actor);
	    if (getOwner() instanceof HouseManager)
		((HouseManager) getOwner()).onHouseDie(this, actor);
	    else if (World.cur().statics != null)
		World.cur().statics.onHouseDied(this, actor);
	}
    }
    
    public void doDieShow() {
	runDeathShow();
    }
    
    public void setDiedFlag(boolean bool) {
	super.setDiedFlag(bool);
	activateMesh();
    }
    
    private void activateMesh() {
	boolean bool = getDiedFlag();
	String string = !bool ? prop.MESH0_NAME : prop.MESH1_NAME;
	if (string == null) {
	    collide(false);
	    drawing(false);
	} else {
	    super.setMesh(string);
	    do {
		if (!bool) {
		    if (prop.bInitHeight0)
			break;
		} else if (prop.bInitHeight1)
		    break;
		int i = mesh().hookFind("Ground_Level");
		float f = 0.0F;
		if (i != -1) {
		    Matrix4d matrix4d = new Matrix4d();
		    mesh().hookMatrix(i, matrix4d);
		    f = (float) -matrix4d.m23;
		} else {
		    float[] fs = new float[6];
		    mesh().getBoundBox(fs);
		    f = -fs[2];
		}
		if (!bool) {
		    prop.bInitHeight0 = true;
		    prop.heightAboveLandSurface0 = f;
		} else {
		    prop.bInitHeight1 = true;
		    prop.heightAboveLandSurface1 = f;
		}
	    } while (false);
	    if (prop.IGNORE_SHADOW_DATA)
		mesh().setFastShadowVisibility(2);
	    else
		mesh().setFastShadowVisibility(1);
	    align();
	    collide(!bool);
	    drawing(true);
	}
    }
    
    public void align() {
	pos.getAbs(p);
	p.z = Engine.land().HQ(p.x, p.y);
	if (!getDiedFlag())
	    p.z += (double) (prop.ADD_HEIGHT_0 + prop.heightAboveLandSurface0);
	else
	    p.z += (double) (prop.ADD_HEIGHT_1 + prop.heightAboveLandSurface1);
	o.setYPR(pos.getAbsOrient().getYaw(), 0.0F, 0.0F);
	if (prop.ALIGN_TO_LAND_NORMAL) {
	    Engine.land().N(p.x, p.y, n);
	    o.orient(n);
	}
	pos.setAbs(p, o);
    }
    
    public Object getSwitchListener(Message message) {
	return this;
    }
    
    public boolean isStaticPos() {
	return true;
    }
    
    public float futurePosition(float f, Point3d point3d) {
	pos.getAbs(point3d);
	if (f <= 0.0F)
	    return 0.0F;
	return f;
    }
    
    public String getShortClassName() {
	return prop.SoftClassInnerName;
    }
    
    static {
	InitTablesOfEnergyToKill();
    }
}
